package com.sailing.xjpb.web.base.utils;

import lombok.Getter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.function.Predicate;

/**
 * 获取已经注入的bean对象
 *
 * @author YaoWei
 */
public class SpringBean implements ApplicationContextAware {

    /**
     * -- GETTER --
     * 获取applicationContext
     */
    @Getter
    private static ApplicationContext applicationContext;

    /**
     * 初始化应用上下文对象ApplicationContext
     *
     * @param applicationContext spring应用上下文
     */
    @Override
    public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
        if (SpringBean.applicationContext == null) {
            SpringBean.applicationContext = applicationContext;
        }
    }

    /**
     * 通过name获取 Bean.
     *
     * @param name bean的名称
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     *
     * @param clazz 类字节码
     * @param <T>   需要获取bean类型
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过class获取Bean.
     *
     * @param name  bean名字
     * @param clazz 类字节码
     * @param <T>   需要获取bean类型
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    /**
     * 获取当前类和当前类子类的所有bean
     *
     * @param clazz 类信息
     */
    public static <T> Collection<T> getBeans(Class<T> clazz) {
        Map<String, T> beans = getBeanInfos(clazz);
        return beans.values();
    }

    /**
     * 获取当前类和当前类子类的所有bean（根据spring order进行排序）
     *
     * @param clazz 类信息
     */
    public static <T> List<T> getSortedBeans(Class<T> clazz) {
        Collection<T> values = getBeans(clazz);
        List<T> sortBeans = new ArrayList<>(values);
        AnnotationAwareOrderComparator.sort(sortBeans);
        return sortBeans;
    }

    /**
     * 获取实现当前类且符合条件的bean
     *
     * @param clazz 类信息
     */
    public static <T> T getBean(Class<T> clazz, Predicate<T> predicate) {
        Map<String, T> beans = getBeanInfos(clazz);
        Collection<T> values = beans.values();
        Optional<T> beanOpt = values.stream().filter(predicate::test).findFirst();
        return beanOpt.orElse(null);
    }

    /**
     * 获取当前类和当前类子类的所有bean
     *
     * @param clazz 类信息
     */
    public static <T> Map<String, T> getBeanInfos(Class<T> clazz) {
        return getApplicationContext().getBeansOfType(clazz);
    }

    /**
     * 获取所有注解类
     */
    public static Map<String, Object> getClassNameByAnnotation(Class<? extends Annotation> clazz) {
        return getApplicationContext().getBeansWithAnnotation(clazz);
    }

}
